package com.lin.manager.task.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lin.manager.common.ex.BizException;
import com.lin.manager.common.req.QueryPage;
import com.lin.manager.common.utils.DateTimeUtil;
import com.lin.manager.common.utils.PageUtil;
import com.lin.manager.task.dao.TaskBusDao;
import com.lin.manager.task.dao.TaskPlainDao;
import com.lin.manager.task.entity.TaskBusEntity;
import com.lin.manager.task.entity.TaskPlainEntity;
import com.lin.manager.task.model.TaskPlainVo;
import com.lin.manager.task.service.TaskService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * @作者: 林江
 * @创建时间: 2024/3/25
 * @功能:
 */
@Transactional
@Service
public class TaskServiceImpl implements TaskService {
    @Autowired
    Scheduler scheduler;
    @Autowired
    TaskBusDao taskBusDao;
    @Autowired
    TaskPlainDao taskPlainDao;

    @PostConstruct
    public void init() throws Exception {
        this.start();
    }

    @Override
    public void saveJob(TaskBusEntity taskBus) throws Exception {
        // 数据库操作
        if (taskBus.getId() != null) {
            taskBusDao.updateById(taskBus);
        } else {
            taskBusDao.insert(taskBus);
        }

        // job
        try {
            Class<?> clazz = Class.forName(taskBus.getClazz());
            if (Job.class.isAssignableFrom(clazz)) {
                Class<? extends Job> cc = (Class<? extends Job>) clazz;
                JobDetail jobDetail = JobBuilder.newJob(cc).withIdentity(createJobKey(taskBus.getId().toString(), taskBus.getCategroy())).withDescription(taskBus.getName()).requestRecovery(true).storeDurably(true) // 持久化
                        .build();

                scheduler.addJob(jobDetail, true);
            } else {
                throw new BizException("任务类型错误,请确认.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException("任务包/类型错误,请确认.");
        }
    }


    @Override
    public void updateJob(TaskBusEntity taskBus) throws Exception {
        TaskBusEntity bus = this.getJob(taskBus.getId().toString());
        JobKey jobKey = createJobKey(bus.getId().toString(), bus.getCategroy());
        // 暂停任务
        scheduler.pauseJob(jobKey);
        if (scheduler.checkExists(jobKey)) {
            // 删除任务
            scheduler.deleteJob(jobKey);
        }
        // 重新添加
        this.saveJob(taskBus);
    }

    @Override
    public TaskBusEntity getJob(String key) throws Exception {
        return taskBusDao.selectById(key);
    }

    @Override
    public void deleteJobById(String key) throws Exception {
        TaskBusEntity job = getJob(key);
        taskBusDao.deleteById(key);
        this.deleteJob(job.getId().toString(), job.getCategroy());
        // 修改trigger为停止状态
        taskPlainDao.updateStatusByJobKey(0, JSON.toJSONString(createJobKey(key, job.getCategroy())));
    }

    @Override
    public void deleteJob(String key, String group) throws Exception {
        JobKey jobKey = createJobKey(key, group);
        scheduler.pauseJob(jobKey);
        //删除任务
        scheduler.deleteJob(jobKey);
    }

    @Override
    public void startJob(String key, String group) throws Exception {
        scheduler.resumeJob(createJobKey(key, group));
    }

    @Override
    public void savePlan(TaskPlainVo taskPlain) throws Exception {
        TaskPlainVo.JobKey job = taskPlain.getJob();
        taskPlain.setJobkey(JSON.toJSONString(job));
        if (StringUtils.isNotBlank(taskPlain.getFormTime())) {
            taskPlain.setStartTime(DateTimeUtil.convertStrToDate(taskPlain.getFormTime()));
        }
        if (StringUtils.isNotBlank(taskPlain.getToTime())) {
            taskPlain.setEndTime(DateTimeUtil.convertStrToDate(taskPlain.getToTime()));
        }
        // 数据库操作
        if (taskPlain.getId() != null) {
            taskPlainDao.updateById(taskPlain);
        } else {
            taskPlainDao.insert(taskPlain);
        }

        // trigger
        TriggerBuilder<Trigger> builder = TriggerBuilder.newTrigger().withIdentity(createTriggerKey(taskPlain.getId().toString(), taskPlain.getCategroy()));

        JobKey jobKey = new JobKey(job.getName(), job.getGroup());
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail == null) {
            throw new BizException("未查询到给定任务,请重试");
        }
        if (taskPlain.getStartTime() != null) {
            builder.startAt(taskPlain.getStartTime());
        }
        if (taskPlain.getEndTime() != null) {
            builder.endAt(taskPlain.getEndTime());
        }
        if (taskPlain.getDescript() != null) {
            builder.withDescription(taskPlain.getDescript());
        }
        Integer type = taskPlain.getType();
        if (type != null) {
            if (type == 0) {
                builder.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(taskPlain.getSeconds()).withRepeatCount(taskPlain.getForever()));
            } else if (type == 1) {

            } else if (type == 2) {
                builder.withSchedule(CronScheduleBuilder.cronSchedule(taskPlain.getCron()));
            }
        } else {
            throw new BizException("请选择触发类型");
        }

        if (scheduler.checkExists(jobKey)) {
            this.deleteJob(jobKey.getName(), jobKey.getGroup());
        }

        Trigger trigger = builder.build();
        scheduler.scheduleJob(jobDetail, trigger); // 为trigger绑定job
        if (taskPlain.getStatus() == 1) {
            scheduler.triggerJob(jobKey);
        } else {
            this.pausePlan(trigger.getKey().getName(), trigger.getKey().getGroup());
        }
    }

    @Override
    public void updatePlan(TaskPlainVo taskPlain) throws Exception {
        TaskPlainEntity plan = getPlan(taskPlain.getId().toString());
        TriggerKey triggerKey = createTriggerKey(plan.getId().toString(), plan.getCategroy());
        if (scheduler.checkExists(triggerKey)) {
            // 删除旧trigger
            this.deletePlan(taskPlain.getId().toString(), taskPlain.getCategroy());
        }
        // 重新绑定
        this.savePlan(taskPlain);
    }

    @Override
    public TaskPlainEntity getPlan(String id) throws Exception {
        return taskPlainDao.selectById(id);
    }

    @Override
    public void pausePlan(String key, String group) throws Exception {
        scheduler.pauseTrigger(createTriggerKey(key, group));
        taskPlainDao.updateStatusById(0, key);
    }

    @Override
    public void startPlan(String key, String group) throws Exception {
        TaskPlainEntity plan = getPlan(key);
        scheduler.resumeTrigger(createTriggerKey(key, plan.getCategroy()));
        taskPlainDao.updateStatusByJobKey(1, plan.getJobkey());
    }

    @Override
    public void deletePlanById(String key) throws Exception {
        TaskPlainEntity taskPlain = taskPlainDao.selectById(key);
        this.deletePlan(taskPlain.getId().toString(), taskPlain.getCategroy());
        // 删除
        taskPlainDao.deleteById(key);
    }

    @Override
    public void deletePlan(String key, String group) throws Exception {
        // 暂停
        this.pausePlan(key, group);
        // 解绑
        scheduler.unscheduleJob(createTriggerKey(key, group));
    }

    @Override
    public void start() throws Exception {
        scheduler.start();
    }

    @Override
    public PageUtil listByPage(QueryPage page) {
        LambdaQueryWrapper<TaskBusEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(TaskBusEntity::getCreateTime);
        String key = page.getKey();
        if (StringUtils.isNotBlank(key)) {
            wrapper.like(TaskBusEntity::getName, key).or().like(TaskBusEntity::getCategroy, key);
        }
        Page<TaskBusEntity> selectPage = taskBusDao.selectPage(new Page<>(page.getPageNum(), page.getPageSize()), wrapper);
        return new PageUtil(selectPage);
    }

    @Override
    public List<TaskBusEntity> list() {
        LambdaQueryWrapper<TaskBusEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(TaskBusEntity::getCreateTime);
        return taskBusDao.selectList(wrapper);
    }

    @Override
    public PageUtil listPlanPage(QueryPage page) {
        LambdaQueryWrapper<TaskPlainEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(TaskPlainEntity::getCreateTime);
        String key = page.getKey();
        if (StringUtils.isNotBlank(key)) {
            wrapper.like(TaskPlainEntity::getName, key).or().like(TaskPlainEntity::getCategroy, key);
        }
        Page<TaskPlainEntity> selectPage = taskPlainDao.selectPage(new Page<>(page.getPageNum(), page.getPageSize()), wrapper);
        return new PageUtil(selectPage);
    }

    @Override
    public List<TaskPlainEntity> listPlan() {
        LambdaQueryWrapper<TaskPlainEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(TaskPlainEntity::getCreateTime);
        return taskPlainDao.selectList(wrapper);
    }

    /**
     * 创建JobKey
     *
     * @param key
     * @param group
     * @return
     */
    private JobKey createJobKey(String key, String group) {
        return new JobKey(key, group);
    }

    private TriggerKey createTriggerKey(String key, String group) {
        return new TriggerKey(key, group);
    }
}
